package com.xinghanlaser.applet.service.impl;


import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.dynamic.datasource.annotation.DSTransactional;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.xinghanlaser.applet.base.auth.entity.UserDO;
import com.xinghanlaser.applet.base.auth.service.IUserService;
import com.xinghanlaser.applet.base.auth.vo.UserPostVO;
import com.xinghanlaser.applet.base.auth.vo.UserPutVO;
import com.xinghanlaser.applet.base.common.entity.ResponseEntity;
import com.xinghanlaser.applet.base.common.exception.ServiceException;
import com.xinghanlaser.applet.entity.DealerSecretKey;
import com.xinghanlaser.applet.entity.UserDetail;
import com.xinghanlaser.applet.service.IAdminService;
import com.xinghanlaser.applet.service.IDealerSecretKeyService;
import com.xinghanlaser.applet.service.IPhoneCodeService;
import com.xinghanlaser.applet.service.IUserDetailService;
import com.xinghanlaser.applet.vo.applet.DealerBindVO;
import com.xinghanlaser.applet.vo.applet.PasswordPutVO;
import com.xinghanlaser.applet.vo.applet.RegisterOrLoginVO;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.RestTemplate;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.HashSet;
import java.util.Optional;
import java.util.Set;

import static com.xinghanlaser.applet.base.common.constant.OAuth2Constant.AUTHORIZATION_HEADER;
import static com.xinghanlaser.applet.constant.AdminConstant.DEALER_ROLE_ID;
import static com.xinghanlaser.applet.constant.AdminConstant.DEFAULT_NICK_NAME;


/**
 * <p>
 *
 * <p>
 *
 * @author: mftuo 陀铭峰
 * @since: 2024/5/3 9:41
 */
@Service
public class AdminServiceImpl implements IAdminService {
    @Resource
    private IUserService userService;

    @Resource
    private RestTemplate restTemplate;

    @Resource
    private IDealerSecretKeyService dealerSecretKeyService;

    @Resource
    private IPhoneCodeService phoneCodeService;

    @Resource
    private IUserDetailService userDetailService;

    @Resource
    private PasswordEncoder passwordEncoder;

    @Value("${auth-url}")
    private String AUTH_URL;

    @Override
    public ResponseEntity<String> registerOrLogin(RegisterOrLoginVO vo, HttpServletRequest request) {
        final String userName = vo.getPhone();

        // 1. 判断是否存在该用户名
        UserDO existUser = userService.getOne(Wrappers.lambdaQuery(new UserDO())
                .select(UserDO::getId, UserDO::getUserName)
                .eq(UserDO::getUserName, userName)
                .last("LIMIT 1")
        );

        boolean isRegister = false;

        // 3. 如果不存在用户，代表是注册
        if(existUser == null){
            isRegister = true;
            this.handleRegister(userName);
        }

        // 4. 如果存在用户，代表是登录，请求Oauth生成JWT
        String token = this.handleLogin(userName, request, isRegister);

        // 5. 清除验证码
        phoneCodeService.clearCode(userName);

        return ResponseEntity.ok(token);
    }

    @Override
    @DSTransactional
    public ResponseEntity<Void> dealerBind(DealerBindVO vo) {
        final String userName = vo.getPhone();
        final String secretKey = vo.getSecretKey();

        // 获取用户信息
        UserDO userEntity = Optional.ofNullable(
            userService.getOne(Wrappers.lambdaQuery(new UserDO())
                .select(UserDO::getUserName, UserDO::getId)
                .eq(UserDO::getUserName, userName)
                .last("LIMIT 1")
            )).orElseThrow(() -> new ServiceException("用户不存在"));

        // 查看是否已经绑定
        DealerSecretKey exist = dealerSecretKeyService.getOne(Wrappers.lambdaQuery(new DealerSecretKey())
                .eq(DealerSecretKey::getBindUserId, userEntity.getId())
                .last("LIMIT 1")
        );
        if(exist != null){
            throw new ServiceException("不可重复绑定");
        }

        // 获取密钥信息
        DealerSecretKey secretKeyEntity = Optional.ofNullable(
            dealerSecretKeyService.getOne(Wrappers.lambdaQuery(new DealerSecretKey())
                .eq(DealerSecretKey::getSecretKey, secretKey)
                .last("LIMIT 1")
        )).orElseThrow(() -> new ServiceException("密钥错误"));

        if(secretKeyEntity.getBindUserId() != null){
            throw new ServiceException("密钥已被绑定");
        }

        // 绑定用户与密钥的关系
        final Long userId = userEntity.getId();
        secretKeyEntity.setBindUserId(userId);
        dealerSecretKeyService.updateById(secretKeyEntity);

        // 绑定用户与角色的关系
        UserPutVO putVO = new UserPutVO();
        putVO.setId(userId);
        Set<Long> roleIds = new HashSet<>();
        roleIds.add(DEALER_ROLE_ID);
        putVO.setRoleIds(roleIds);
        userService.modUser(putVO);

        return ResponseEntity.okMsg("绑定成功");
    }

    @Override
    @DSTransactional
    public ResponseEntity<Void> updatePassword(PasswordPutVO vo) {
        final String phone = vo.getPhone();
        final String password = vo.getPassword();

        // 更改详情密码
        userDetailService.updatePassword(phone, password);

        // 更改基本密码
        userService.update(Wrappers.lambdaUpdate(new UserDO())
                .eq(UserDO::getUserName, phone)
                .set(UserDO::getPassword,  passwordEncoder.encode(password))
        );

        // 删除验证码
        phoneCodeService.clearCode(phone);

        return ResponseEntity.okMsg("更改密码成功");
    }

    private void handleRegister(String userName){
        // 添加用户
        UserPostVO postVO = new UserPostVO();
        postVO.setUserName(userName);
        postVO.setNickName(DEFAULT_NICK_NAME + userName);

        userService.addUser(postVO);

        // 添加额外信息
        userDetailService.addUserDetail(userName);
    }

    private String handleLogin(String userName, HttpServletRequest request, boolean isRegister){
        String authorization = request.getHeader(AUTHORIZATION_HEADER);

        if(StrUtil.isBlank(authorization)){
            throw new ServiceException("未携带Token");
        }

        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.set("Authorization", authorization);

        // 获取密码
        String password = userDetailService.getPasswordByUserName(userName);

        // 创建请求体，包含表单数据
        MultiValueMap<String, String> map = new LinkedMultiValueMap<>();
        map.add("username", userName);
        map.add("password", password);

        // 创建HttpEntity，包含请求头和请求体
        HttpEntity<MultiValueMap<String, String>> requestEntity = new HttpEntity<>(map, headers);

        // 发送POST请求
        try {
            org.springframework.http.ResponseEntity<String> response = restTemplate.postForEntity(AUTH_URL, requestEntity, String.class);

            ResponseEntity result = JSONUtil.toBean(response.getBody(), ResponseEntity.class);

            if(result.getCode() != 0 && isRegister){
                userService.remove(Wrappers.lambdaQuery(new UserDO()).eq(UserDO::getUserName, userName));
                userDetailService.remove(Wrappers.lambdaQuery(new UserDetail()).eq(UserDetail::getUserName, userName));
                throw new ServiceException(result.getMsg());
            }

            return result.getData().toString();
        }catch (Exception e){
            if(isRegister){
                userService.remove(Wrappers.lambdaQuery(new UserDO()).eq(UserDO::getUserName, userName));
                userDetailService.remove(Wrappers.lambdaQuery(new UserDetail()).eq(UserDetail::getUserName, userName));
            }
            throw new ServiceException("授权服务认证请求失败");
        }
    }

}
